/** The file exporting class.
 * @author Sauvik Das
 */

package com.type.TypingDetector;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;


import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.AssetManager;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;


public class LearningMode extends Activity {
	private SensorManager sm;
    private List<Sensor> sensors;
    private Sensor accel;
    private Sensor orientation;
    boolean accelerometerAvailable = false;
    boolean isEnabled = false;
    TextView accelText;
    TextView diffText;
    CheckBox recDat;
    ToggleButton enabled;
    EditText fileName, delActiv;
    RadioButton rbTxt;
    RadioButton rbCsv;
    boolean active=false, first=true, mStoragePossible=false;
    int counter;
    //final int scaleVal=10;//100000000
    double[] dataArr;
    BufferedWriter writer, dbWriter;
    String extension=".csv";
    String folderName;
    public static final String TYPE = "type";
    private XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset();
    private XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
    private XYSeries mCurrentSeries;
    private XYSeriesRenderer mCurrentRenderer;
    private String mDateFormat;
    private GraphicalView mChartView;
    private long time;
    private boolean firstG=true, firstDB=true;
    Button dbButton, delButton, serverButton;
    private final int SMOOTH_ITERATIONS=1;
    private final String PATH_TO_FILE="data/data/com.type.TypingDetector";
    private final String FOLDER_NAME="SavedFiles";
    boolean recToDB=false;
    private String currFN="";
    private int nextID;
    private int nextDBID;
    private final int GESTURE_RECOG=1;
    private int startIndex=0;
    private int endIndex=511;
   
    private boolean waiting=false;
    private AlertDialog restartApp;
    
    //private ArrayList<Double> recdVals;
    private ArrayList<Double> recdValsX;
    private ArrayList<Double> recdValsY;
    private ArrayList<Double> recdValsZ;
    
    //Database stuff
    protected final String DATABASE_TABLE="AccelValues4";
    protected final String FN_TABLE="Filenames4";
    protected ArrayList<String> colNames= new ArrayList<String>(Arrays.asList("Title", "XDom", "XAvg", "XMax", "XMin", "YDom", "YAvg", "YMax", "YMin", "ZDom", "ZAvg", "ZMax", "ZMin", "Filename"));
    protected ArrayList<String> colOpts= new ArrayList<String>(Arrays.asList("text","real","real","real","real","real","real","real","real","real","real","real","real", "text"));
    protected ArrayList<String> rowNames; //new ArrayList<String>(Arrays.asList("Phone Detached", "Idle", "Walking", "Running", "Jumping"));
    protected ArrayList<String> rowFileNames= new ArrayList<String>();
    protected ArrayList<String> rowFileTypes= new ArrayList<String>();
    protected ArrayList<String> fileNames;//= new ArrayList<String>(Arrays.asList("tabletopnew.txt", "sittingnew.txt", "walkingnewb.txt", "runningnewb.txt", "jumpingnewb.txt"));
    protected ArrayList<String> fntbColNames = new ArrayList<String>(Arrays.asList("Type","Filename"));
    protected ArrayList<String> fntbColOpts = new ArrayList<String>(Arrays.asList("text","text"));
    private DatabaseQuery query, fnQuery;
    //private final String fnRowIDName="rowid";
    private final String dbRowIDName="_id";
    
    //TCP Communication Stuff
    private boolean mSocketAvl=false;
    private Socket socket; //Socket used to communicate with server
    private String serverPacket;
    private final String mIPAddr="128.2.142.39";
    private final int portNo=6002;
    private BufferedReader in;
    private PrintWriter out;
    private final String TRANSMIT_OVER="Done";
    private final String DATABASE_DATA_FN="DBData";
    
    /** This is a hacked workaround to keep the accelerometer active even while the screen is off
     * 
     * @param mReciever - A broadcast reciever which recieves the intent ACTION_SCREEN_OFF. Registered in onCreate. 
     */
    protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
    	public void onReceive(Context context, Intent intent) {
    		if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
    			sm.unregisterListener(mySEL);
    			sm.registerListener(mySEL, accel, SensorManager.SENSOR_DELAY_FASTEST);
    			}
    		}
    	};
    
    /** This method restores important data to the Activity if it is killed by the system and restarted
     * More information available in Android Docs.
     * @param savedState - The saved values set by onSaveInstanceState	
     */
    @Override
    	 protected void onRestoreInstanceState(Bundle savedState) {
    	  	super.onRestoreInstanceState(savedState);
    	    mDataset = (XYMultipleSeriesDataset) savedState.getSerializable("dataset");
    	    mRenderer = (XYMultipleSeriesRenderer) savedState.getSerializable("renderer");
    	    mCurrentSeries = (XYSeries) savedState.getSerializable("current_series");
    	    mCurrentRenderer = (XYSeriesRenderer) savedState.getSerializable("current_renderer");
    	    mDateFormat = savedState.getString("date_format");
    	    //sm = (SensorManager) savedState.getSerializable("SensorManager");
    	    firstG=savedState.getBoolean("first");
    	    time=savedState.getLong("time");
    	  }

    /** This method saves important data if the system kills Activity forcefully, such as when orientation is changed
     * More information available in Android Docs.
     */
    	  @Override
    	  protected void onSaveInstanceState(Bundle outState) {
    	    super.onSaveInstanceState(outState);
    	    outState.putSerializable("dataset", mDataset);
    	    outState.putSerializable("renderer", mRenderer);
    	    outState.putSerializable("current_series", mCurrentSeries);
    	    outState.putSerializable("current_renderer", mCurrentRenderer);
    	    outState.putString("date_format", mDateFormat);
    	    outState.putLong("time", time);
    	    //outState.putSerializable(key, value);
    	    outState.putBoolean("first", firstG);
    	  }
    
    /** This method creates the layout of the Activity and initializes most global variables and sensors.
     * If onRestoreInstanceState was called before this method (meaning this is not the first time the Activity has been
     * opened, then the variable initializations are bypassed, and only the sensors are initialized.
     */
    	  
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.lmode);
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //keeps screen orientation in portrait mode
		accelerometerAvailable = instantiateSensors();
		
		AlertDialog.Builder builderb = new AlertDialog.Builder(this);
        final AlertDialog settings;
        
        builderb.setCancelable(false);
        builderb.setMessage("File Settings:");
        LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.custom_dialog,
                null);
        
        
        final EditText forTest= (EditText)findViewById(R.id.forTesting);
		fileName=(EditText) layout.findViewById(R.id.editTextD);
		recDat=(CheckBox) layout.findViewById(R.id.recDBD);
		rbTxt = (RadioButton) layout.findViewById(R.id.radio_txtD);
        rbCsv = (RadioButton) layout.findViewById(R.id.radio_csvD);
		//delActiv=(EditText) findViewById(R.id.delActiv);
		enabled=(ToggleButton) findViewById(R.id.togglebutton2);
		folderName=getString(R.string.appFolderName);
		dbButton=(Button) findViewById(R.id.dbButton);
		delButton=(Button) findViewById(R.id.delButton);
		serverButton=(Button) findViewById(R.id.server);
		serverButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				//Toast.makeText(getApplicationContext(), "Trying", Toast.LENGTH_SHORT);
				try {
					if (socket==null) {
						socket=new Socket(mIPAddr, portNo);
						in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
						out=new PrintWriter(socket.getOutputStream(), true);
						forTest.setText("Connected");
						mSocketAvl=true;
					}
		    	 }
		    	 catch (IOException e) {
		    	 	mSocketAvl=false;
		    	 	forTest.setText("Failure");
		    	 }
		    	 
		    	 if (mSocketAvl) {
		    		InfoDatObject[] idos=getIDOsFromDB();
		    		out.println(DATABASE_DATA_FN);
		    		ArrayList<String> uniqueRNs=fnQuery.getDataNS(new String[] {"Type"}, null, null, null, null);
		    		ArrayList<String> dummy=new ArrayList<String>();
		    		String t="";
		    		for (int i=0; i<uniqueRNs.size();i++) {
		    			if (!dummy.contains(uniqueRNs.get(i))) {
		    				t+=uniqueRNs.get(i)+",";
		    				dummy.add(uniqueRNs.get(i));
		    			}
		    		}
		    		t=t.substring(0, t.length()-1);
		    		out.println(t);
		    		out.println("L");
					for (int i=0; i<idos.length; i++) {
						String val=writeServerPacket(idos[i]);
						out.write(val, 0, val.length());
						out.println();
						//out.flush();
					}
					forTest.setText("Completed");
					out.println(TRANSMIT_OVER);
					try {
						socket.close();
						in.close();
						socket=null;
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					out.close();
					mSocketAvl=false;
		    	 }
				
				
			}
			
		});
        
		builderb.setView(layout);
		
		recDat.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				//CheckBox v2=(CheckBox)v;
				recToDB=((CheckBox)v).isChecked();
			}
			
		});
		
		final OnClickListener radio_list = new OnClickListener() {
        	public void onClick(View v) {
        		RadioButton rbu = (RadioButton)v;
        		extension = (String) rbu.getText();
        	}
        };
        
        rbTxt.setOnClickListener(radio_list);
        rbCsv.setOnClickListener(radio_list);
        
        if (extension.compareTo(".csv")==0) {rbCsv.toggle();}
        else {rbTxt.toggle();}
        builderb.setPositiveButton("OK", new DialogInterface.OnClickListener() {
	           public void onClick(DialogInterface dialog, int id) {
	        	   initializeWriter();
	        	   active=true;
	        	   dialog.dismiss();
	           }
	       });
        settings=builderb.create();
        settings.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
        
        
		
		if (query==null) query=new DatabaseQuery(this, colNames, colOpts, DATABASE_TABLE);
		if (fnQuery==null) fnQuery=new DatabaseQuery(this, fntbColNames, fntbColOpts, FN_TABLE);
		/*String[] fntypes={"Phone Detached", "Idle Sitting/Standing", "Walking", "Running", "Jumping", "Climbing Stairs", "Riding Bus", "Activity", "Descending Stairs"};
		String[] fns={"tabletopnew.txt", "sittingnew.txt", "walkingnewb.txt", "runningnewb.txt", "jumpingnewb.txt", "stairsup.txt", "bus28x.txt", "activity.txt", "stairsdown.txt"};
		for (int j=0; j<fns.length; j++) {
			fnQuery.appendData("ID", ""+j);
			fnQuery.appendData("Type", fntypes[j]);
			fnQuery.appendData("Filename", fns[j]);
			fnQuery.addRow();
		}*/
		
		fileNames=fnQuery.getDataNS(new String[] {"Filename"}, null, null, null, null);
		rowNames=fnQuery.getDataNS(new String[] {"Type"}, null, null, null, null);
		nextID=fileNames.size();
		
		final AssetManager am = getAssets();
		
		AlertDialog.Builder resApp = new AlertDialog.Builder(this);
		resApp.setMessage("Restart application for changes to take effect.");
		resApp.setPositiveButton("OK", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				dialog.dismiss();
			}
			
		});
		
		restartApp=resApp.create();
		
		dbButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {				
				try {
					fnQuery.clearTable();
					for (int j=0; j<rowFileTypes.size(); j++) {
						fnQuery.appendData("Type", rowFileTypes.get(j));
						fnQuery.appendData("Filename", rowFileNames.get(j));
						fnQuery.addRow();
					}
					query.clearTable();
					fileNames=fnQuery.getDataNS(new String[] {"Filename"}, null, null, null, null);
					rowNames=fnQuery.getDataNS(new String[] {"Type"}, null, null, null, null);
					for (int j=0; j<fileNames.size();j++) {
						InfoDatObject ido;
						if (rowFileNames.contains(fileNames.get(j)))
							ido=parseFiles(am.open(fileNames.get(j), AssetManager.ACCESS_STREAMING));
						else
							ido=parseFiles(new FileInputStream(PATH_TO_FILE+"/"+FOLDER_NAME+"/"+fileNames.get(j)));
						
						query.appendData("Title", "" + rowNames.get(j));
						query.appendData("XDom", "" + (ido.getfFreqs())[0]);
						query.appendData("XAvg", "" + (ido.getAvgs())[0]);
						query.appendData("XMax", "" + (ido.getMaxes())[0]);
						query.appendData("XMin", "" + (ido.getMins())[0]);
						query.appendData("YDom", "" + (ido.getfFreqs())[1]);
						query.appendData("YAvg", "" + (ido.getAvgs())[1]);
						query.appendData("YMax", "" + (ido.getMaxes())[1]);
						query.appendData("YMin", "" + (ido.getMins())[1]);
						query.appendData("ZDom", "" + (ido.getfFreqs())[2]);
						query.appendData("ZAvg", "" + (ido.getAvgs())[2]);
						query.appendData("ZMax", "" + (ido.getMaxes())[2]);
						query.appendData("ZMin", "" + (ido.getMins())[2]);
						query.appendData("Filename", fileNames.get(j));
						query.addRow();
						//query.addRow();
					}
					restartApp.show();
				}
				catch (FileNotFoundException e) {
					//diffText.setText("File not Found");
				}
				catch (IOException e) {
					//diffText.setText("meh");
				}
        	}
		});
		
		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Pick which Activity to Delete");
		String[] titls=fileNames.toArray(new String[fileNames.size()]);
		final ArrayAdapter<String> adapt = new ArrayAdapter(this, R.layout.vislist, fileNames);
		builder.setAdapter(adapt, new DialogInterface.OnClickListener() {
		    public void onClick(DialogInterface dialog, int item) {
		    	ListView lv=((AlertDialog)dialog).getListView();
		        query.deleteRow(new String[] {dbRowIDName, colNames.get(colNames.size()-1)}, (String)lv.getItemAtPosition(item));
				fnQuery.deleteRow(new String[] {dbRowIDName, fntbColNames.get(1)}, (String)lv.getItemAtPosition(item));
				adapt.remove(adapt.getItem(item));
				adapt.notifyDataSetChanged();
				restartApp.show();
		    }
		});
		final AlertDialog alert = builder.create();
		//alert.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
		
		delButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				alert.show();
				fileNames=fnQuery.getDataNS(new String[] {"Filename"}, null, null, null, null);
				rowNames=fnQuery.getDataNS(new String[] {"Type"}, null, null, null, null);
				
			}
		});
		
		/*ArrayList<String> lastIDcheck= fnQuery.getDataNS(new String[] {"ID"}, null, null, null, null);
		nextDBID=-1;
		for (int i=0; i<lastIDcheck.size(); i++) {
			if (nextDBID<Integer.valueOf(lastIDcheck.get(i))) {
				nextDBID=Integer.valueOf(lastIDcheck.get(i));
			}
		}*/
		//nextDBID++;
		//need to add OnClickListener to button
		final LDataObject data = (LDataObject) getLastNonConfigurationInstance(); //to reinitialize non-serializable objects
		if (data!=null) {
			dataArr=data.dataArr;
			counter=data.counter;
			active=data.active;
			extension=data.extension;
			writer=data.writer;
			first=data.first;
			mStoragePossible=data.mStoragePossible;
			fileName.setText(data.fileName);
		}
		else {
			dataArr = new double[200];
			counter = 0;
		}
		
		Random generator=new Random(6);
		/*if (mCurrentRenderer==null) {
			String[] seriesTitle = {"X Magnitudes", "Y Magnitudes", "Z Magnitudes"};
		    int[] colors=new int[seriesTitle.length];
			for (int k=0; k<colors.length; k++) {
				colors[k]=Color.rgb(generator.nextInt(255), generator.nextInt(255), generator.nextInt(255));
			}
		    for (int i=0; i<3; i++) {
		    	XYSeries series = new XYSeries(seriesTitle[i]);
		    	mDataset.addSeries(series);
		    	XYSeriesRenderer renderer = new XYSeriesRenderer();
		    	renderer.setLineWidth(2.0f);
		    	renderer.setColor(colors[i]);
		    	mRenderer.addSeriesRenderer(renderer);
		    }
		    mCurrentSeries=mDataset.getSeriesAt(0);
			mCurrentRenderer=(XYSeriesRenderer) mRenderer.getSeriesRendererAt(0);
	    }*/
		
		
		
        
        
        
        registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); //for the partial wake lock
        
        
        
		enabled.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				//active=
				if (enabled.isChecked()) {
					settings.show();
				}
				else {
					try {
						if (writer != null){
							writer.close();
						}
						if (recToDB) {
							Intent i=new Intent(Intent.ACTION_CHOOSER);
							//i.setClassName("com.accel.accelerometer", "GestureRecognition");
							//i.putExtra("filename", ""+fileName.getText()+extension);
							//Double[] da=recdVals.toArray(new Double[recdVals.size()]);
							double[] dAX=new double[recdValsX.size()];
							double[] dAY=new double[recdValsY.size()];
							double[] dAZ=new double[recdValsZ.size()];
							for (int l=0; l<dAX.length; l++) {
								dAX[l]=recdValsX.get(l);
								dAY[l]=recdValsY.get(l);
								dAZ[l]=recdValsZ.get(l);
							}
							i.putExtra("xVals", dAX);
							i.putExtra("yVals", dAY);
							i.putExtra("zVals", dAZ);
							waiting=true;
							startActivityForResult(i,GESTURE_RECOG);
							//restartApp.show();
						}
					}
					catch (IOException e) {
						Log.e("error", e.toString());
					}
				}
			}
        });
		
		if (accelerometerAvailable)
        {
        	sm.registerListener(mySEL, accel, SensorManager.SENSOR_DELAY_FASTEST);
        }
		if(time==0) {time=SystemClock.uptimeMillis();}
        //accelText.setText("[0.0]");
        
	}
	
	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dlog = new Dialog(this);
		dlog.setContentView(R.layout.custom_dialog);
		dlog.setTitle("Configuration");
		dlog.setCancelable(false);
		return dlog;
	}
	private void recordToDatabase(int nID, String timeStamp, String acName, String ext) {
		//fnQuery.appendData("ID", ""+nID);
		fnQuery.appendData("Type", acName);
		fnQuery.appendData("Filename", timeStamp+acName+ext);
		fnQuery.addRow();
	}
	
	/** Called if the activity is paused and then reopened
	 * 
	 */
	protected void onResume() {
	    super.onResume();
	    if (mChartView == null) {
	      LinearLayout layout = (LinearLayout) findViewById(R.id.chart);
	      mChartView = ChartFactory.getLineChartView(this, mDataset, mRenderer);
	      layout.addView(mChartView, new LayoutParams(LayoutParams.FILL_PARENT,
	          LayoutParams.FILL_PARENT));
	      //boolean enabled = mDataset.getSeriesCount() > 0;
	      //setSeriesEnabled(enabled);
	    } else {
	      mChartView.repaint();
	    }
	  }
	
	/** Initiates the SensorManager and Accelerometer.
	 * 
	 * @return - true if the initialization was a success, false otherwise
	 */
	private boolean instantiateSensors() {
		// TODO Auto-generated method stub
		sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        sensors = sm.getSensorList(Sensor.TYPE_ACCELEROMETER);
        
        if (sensors.size() > 0) {
        	accel = sensors.get(0);
        	return true;}
        return false;
    }
	
	/** The SensorEventListener for the accelerometer. Called whenever the sensor values are changed.
	 * 
	 */
	private final SensorEventListener mySEL = new SensorEventListener() {
		/** First converts the three sensor values into one via Pythagorean theorem, then plots this point against
		 * time(in milliseconds). If Exporting is enabled, it also writes this value into the specified file.
		 * 
		 * @param event - The event values
		 */
		public void onSensorChanged(SensorEvent event) {
			double val=Math.sqrt(Math.pow(event.values[0],2) + Math.pow(event.values[1],2) + Math.pow(event.values[2],2));	
			dataArr[counter]=val;
				//displayAccelValues(dataArr[counter]);
				if ((SystemClock.uptimeMillis()-time)>30000) {
					firstG=false;
				}
				
				/*if (!firstG) {
					for (int i=0; i<mDataset.getSeriesCount(); i++) {
						mDataset.getSeriesAt(i).remove(0);
					}
				}
				
				for (int i=0; i<event.values.length; i++) {
					mCurrentSeries=mDataset.getSeriesAt(i);
					mCurrentRenderer=(XYSeriesRenderer) mRenderer.getSeriesRendererAt(i);
					mCurrentSeries.add(SystemClock.uptimeMillis()-time, event.values[i]);
				}
				
				if (mChartView != null) {
			          mChartView.repaint();
			    }*/
				
				if (active) {
					//String toWrite = "[" + dataArr[counter][0] + "," + dataArr[counter][1] + "," +dataArr[counter][2] + "]";
					String toWrite = ""+ event.values[0]+ "," + event.values[1]+ "," + event.values[2];
					try {
						if (mStoragePossible) {
							writer.write(toWrite, 0, toWrite.length());
							writer.newLine();
						}
						if (recToDB) {
							//dbWriter.write(toWrite, 0, toWrite.length());
							//dbWriter.newLine();
							recdValsX.add((double)(event.values[0]));
							recdValsY.add((double)(event.values[1]));
							recdValsZ.add((double)(event.values[2]));
						}
					}
					catch (IOException e) {
						Log.e("error", e.toString());
					}
					
				}
				counter++;
				if (counter>=199) {
					counter=0;
				}
		}
		
		public void onAccuracyChanged(Sensor sensor, int accuracy) {
			
		}
	};
	
	public void displayAccelValues(double vals) {
		DecimalFormat df = new DecimalFormat("##0.00000");
		//accelText.setText("[" + df.format(vals) + "]");
		//if (!first) {
			//diffText.setText("[" + df.format(differences[0]) + "," + df.format(differences[1]) + "," + df.format(differences[2]) + "]");
		//}
	}
	
	/** Saves data which needs to be retained when application is destroyed. Differs from onSaveInstanceState
	 * and onRestoreInstanceState() in that this data does not need to be Serializable, and is simply stored as 
	 * an instance of Object. Requires self-wrote class to save the data
	 * 
	 */
	@Override
	public Object onRetainNonConfigurationInstance() {
	    final LDataObject data = new LDataObject(dataArr, counter, active, extension, writer, first, fileName.getText().toString(), mStoragePossible);
	    return data;
	}
	
	/** This method parses files to initialize the staticVals array with the data accrued from LearningMode.
	 * 
	 * @param strm The Input Stream of the files to be read
	 * @param index The PREDICTION_TYPE index indicating the type of data the current Stream is referring too
	 * @return A comparison object with the average and fundamental frequency
	 * @throws FileNotFoundException
	 */
	private InfoDatObject parseFiles(InputStream strm) throws FileNotFoundException {
		Scanner scan=new Scanner(strm);
		ArrayList<Double> dataX=new ArrayList<Double>(); //don't know size, so ArrayList
		ArrayList<Double> dataY=new ArrayList<Double>();
		ArrayList<Double> dataZ=new ArrayList<Double>();
		scan.useDelimiter(",");
		scan.nextLine(); //throw out first line
		while (scan.hasNextLine()) { //must be formatted as xval, yval, zval
			String temp=scan.nextLine();
			double xVal;
			double yVal;
			double zVal;
			
			if (temp!="" && scan.hasNextLine()) {
				String[] tmp=temp.split(",");
				xVal=Double.valueOf(tmp[0]);
				yVal=Double.valueOf(tmp[1]);
				zVal=Double.valueOf(tmp[2]);
				//double storVal = Double.valueOf(temp);
				dataX.add(xVal);
				dataY.add(yVal);
				dataZ.add(zVal);
			}
		}
		
		
		return parseData(dataX,dataY,dataZ);
	}
	
	/** This method parses files to initialize the staticVals array with the data accrued from LearningMode.
	 * 
	 * @param strm The Input Stream of the files to be read
	 * @param index The PREDICTION_TYPE index indicating the type of data the current Stream is referring too
	 * @return A comparison object with the average and fundamental frequency
	 * @throws FileNotFoundException
	 */
	private InfoDatObject parseData(ArrayList<Double> xVals, ArrayList<Double> yVals, ArrayList<Double> zVals) throws FileNotFoundException {
		/*Scanner scan=new Scanner(strm);
		ArrayList<Double> data=new ArrayList<Double>(); //don't know size, so ArrayList
		scan.useDelimiter(",");
		scan.nextLine(); //throw out first line
		while (scan.hasNextLine()) { //must be formatted as xval, yval, zval
			String temp=scan.nextLine();
			if (temp!="") {
				double storVal = Double.valueOf(temp);
				data.add(storVal);
			}
		}*/
		
		double[] datX=new double[xVals.size()];
		double[] datY=new double[yVals.size()];
		double[] datZ=new double[zVals.size()];
		for (int j=0; j<xVals.size(); j++) {
			datX[j]=xVals.get(j).doubleValue();
			datY[j]=yVals.get(j).doubleValue();
			datZ[j]=zVals.get(j).doubleValue();
		}
		
		for (int j=0; j<SMOOTH_ITERATIONS; j++) {
			datX=AcceleromterUpdated.smoothValues(datX);
			datY=AcceleromterUpdated.smoothValues(datY);
			datZ=AcceleromterUpdated.smoothValues(datZ);
		}
		
		double[] datRX = new double[FourierTransform.nextPowerOfTwo(xVals.size())];
		double[] datIX = new double[datRX.length];
		double[] datRY = new double[FourierTransform.nextPowerOfTwo(yVals.size())];
		double[] datIY = new double[datRY.length];
		double[] datRZ = new double[FourierTransform.nextPowerOfTwo(zVals.size())];
		double[] datIZ = new double[datRZ.length];
		
		double datMaxX=0,datMaxY=0,datMaxZ=0;
		double datMinX=Double.MAX_VALUE, datMinY=Double.MAX_VALUE, datMinZ=Double.MAX_VALUE;
		double cTotX=0.0, cTotY=0.0, cTotZ=0.0;
		
		for (int j=0; j<datRX.length; j++) {
		 	if (j<datX.length) {
		 		if (datX[j]>datMaxX) {
		 			datMaxX=datX[j];
		 		}
		 		if (datX[j]<datMinX) {
		 			datMinX=datX[j];
		 		}
		 		if (datY[j]>datMaxY) {
		 			datMaxY=datY[j];
		 		}
		 		if (datY[j]<datMinY) {
		 			datMinY=datY[j];
		 		}
		 		if (datZ[j]>datMaxZ) {
		 			datMaxZ=datZ[j];
		 		}
		 		if (datZ[j]<datMinZ) {
		 			datMinZ=datZ[j];
		 		}
		 		datRX[j] = datX[j]; datRY[j] = datY[j]; datRZ[j] = datZ[j];
				cTotX+=datRX[j]; cTotY+=datRY[j]; cTotZ+=datRZ[j];
			}
			else { //pad with 0s
				datRX[j]=0.0; datRY[j]=0.0; datRZ[j]=0.0;
			}
			datIX[j]=0.0; datIY[j]=0.0; datIZ[j]=0.0;
		}
		
		double avgX = cTotX/(xVals.size()), avgY=cTotY/(yVals.size()), avgZ=cTotZ/(zVals.size());
		FastFourierTransform.fastFT(datRX, datIX, true);
		FastFourierTransform.fastFT(datRY, datIY, true);
		FastFourierTransform.fastFT(datRZ, datIZ, true);
		double fFreqX = findAvgFundamentalFreq(datRX, datIX);
		double fFreqY = findAvgFundamentalFreq(datRY, datIY);
		double fFreqZ = findAvgFundamentalFreq(datRZ, datIZ);
		//scan.close();
		
		return new InfoDatObject(new double[] {fFreqX, fFreqY, fFreqZ}, new double[] {avgX, avgY, avgZ}, new double[] {datMaxX, datMaxY, datMaxZ}, new double[] {datMinX, datMinY, datMinZ});
	}
	
	/** Finds the fundamental frequency of the Fourier Transformed data passed in.
	 * 
	 * @param real The real part of the data
	 * @param imag The imaginary part of the data
	 * @return the fundamental frequency of the data
	 */
	public double findFundamentalFreq(double[] real, double[] imag) {
		double currMax = 0;
		double retVal=-1;
		for (int i=0; i <real.length; i++) {
			double mag = Math.sqrt(Math.pow(real[i],2)+Math.pow(imag[i],2));
			if (mag > currMax) retVal=i;
		}
		return retVal;
	}
	
	public double findAvgFundamentalFreq(double[] real, double[] imag) {
		double retVal=-1;
		double[] maxes=new double[3];
		double minMax=0;
		int maxCounter=0;
		
		for (int i=0; i <real.length; i++) {
			double mag = Math.sqrt(Math.pow(real[i],2)+Math.pow(imag[i],2));
			if (mag > minMax) {
				if (maxCounter<2) {
					maxes[maxCounter] = mag;
					maxCounter++;
				}
				else {
					//find lowest of the current maxes
					double min=Double.MAX_VALUE;
					int indexOfLowest=0;
					for (int j=0; j<maxes.length;j++) {
						if (maxes[j]<min) {min=maxes[j];}
						indexOfLowest=j;
					}
					maxes[indexOfLowest]=mag;
					minMax=mag;
				}
			}		
		}
		return (double)((maxes[0]+maxes[1]+maxes[2])/3);
	}
	
	protected void initializeWriter() {
		try {
			if (first) {
				File f = new File("/sdcard/" + folderName);
				if (f.exists()) {
					first = !first;
				}
				else {
					first = new File("/sdcard/" + folderName).mkdir();
				}
			}
			
			if (recToDB) {
				if (firstDB) {
					File g = new File(PATH_TO_FILE + "/" + FOLDER_NAME);
					if (g.exists()) {
						firstDB = !firstDB;
					}
					else {
						firstDB = new File(PATH_TO_FILE + "/" + FOLDER_NAME).mkdir();
					}
				}
				/*dbWriter=new BufferedWriter(new FileWriter(PATH_TO_FILE + "/" + FOLDER_NAME + "/" + fileName.getText() + extension));
				//Scanner s=new Scanner(new File("/sdcard/" + folderName + "/" + currFN + extension));
				String toWrite="Acceleration Values";
				dbWriter.write(toWrite, 0, toWrite.length());
				dbWriter.newLine();*/
				recdValsX=new ArrayList<Double>();
				recdValsY=new ArrayList<Double>();
				recdValsZ=new ArrayList<Double>();
			}
			
			if (!first) {
				String tmName="/sdcard/" + folderName + "/" + fileName.getText() + extension;
				writer= new BufferedWriter(new FileWriter(tmName));
				currFN="" + fileName.getText();
				String toWrite="Acceleration Values";
				writer.write(toWrite, 0, toWrite.length());
				writer.newLine();
				mStoragePossible=true;
			}
			
		}
		catch (IOException e) {
			mStoragePossible=false;
			fileName.setText(extension);
		}
	}
	
	protected void onActivityResult(int requestCode, int resultCode, Intent data){
	    // See which child activity is calling us back.
	    switch (requestCode) {
	        case GESTURE_RECOG:
	            // This is the standard resultCode that is sent back if the
	            // activity crashed or didn't doesn't supply an explicit result.
	        	String tmp;
	            if (resultCode == RESULT_CANCELED){
	                //myMessageboxFunction("Fight cancelled");
	            	startIndex=0;
	            	endIndex=511;
	            } 
	            else {
	            	Bundle b=data.getExtras();
	            	startIndex=b.getInt("startCounter");
	            	endIndex=b.getInt("endCounter");
	            }
	            try {
	            	java.sql.Timestamp ct=new java.sql.Timestamp(Calendar.getInstance().getTime().getTime());
	            	tmp=ct.toString();
	            	tmp=tmp.substring(5,10)+"-"+tmp.substring(11,19)+"-";
	            	dbWriter=new BufferedWriter(new FileWriter(PATH_TO_FILE + "/" + FOLDER_NAME + "/" + tmp + fileName.getText() + extension));
	            	String toWrite="Acceleration Values";
	            	dbWriter.write(toWrite, 0, toWrite.length());
	            	dbWriter.newLine();
	            	for (int i=startIndex; i<=endIndex; i++) {
	            		if (i<recdValsX.size()) {
	            			toWrite=""+recdValsX.get(i)+","+recdValsY.get(i)+","+recdValsZ.get(i);
	            			dbWriter.write(toWrite, 0, toWrite.length());
	            			dbWriter.newLine();
	            		}
	            	}
					dbWriter.close();
					if (recToDB) {
						recordToDatabase(nextID, tmp, "" +fileName.getText(), extension);
						//Comparison c = parseFiles(new FileInputStream(PATH_TO_FILE+"/"+FOLDER_NAME+"/"+fileName.getText()+extension),0);
						InfoDatObject ido = parseData(recdValsX, recdValsY, recdValsZ);
						query.appendData("Title", "" + fileName.getText());
						query.appendData("XDom", "" + (ido.getfFreqs())[0]);
						query.appendData("XAvg", "" + (ido.getAvgs())[0]);
						query.appendData("XMax", "" + (ido.getMaxes())[0]);
						query.appendData("XMin", "" + (ido.getMins())[0]);
						query.appendData("YDom", "" + (ido.getfFreqs())[1]);
						query.appendData("YAvg", "" + (ido.getAvgs())[1]);
						query.appendData("YMax", "" + (ido.getMaxes())[1]);
						query.appendData("YMin", "" + (ido.getMins())[1]);
						query.appendData("ZDom", "" + (ido.getfFreqs())[2]);
						query.appendData("ZAvg", "" + (ido.getAvgs())[2]);
						query.appendData("ZMax", "" + (ido.getMaxes())[2]);
						query.appendData("ZMin", "" + (ido.getMins())[2]);
						query.appendData("Filename", "" + tmp + fileName.getText() + extension);
						query.addRow();
					}
					nextID++;
					nextDBID++;
					waiting=false;
					restartApp.show();
	            } 
	            catch (IOException e) {
				// TODO Auto-generated catch block
	            	e.printStackTrace();
	            }
				//Scanner s=new Scanner(new File("/sdcard/" + folderName + "/" + currFN + extension));
				
	        default:
	            break;
	    }
	}
	
	@Override
	protected void onDestroy() {
		try {
			if (writer!=null)
				writer.close();
			if (dbWriter!=null)
				dbWriter.close();
			/*if (waiting) {
				startIndex=0;
            	endIndex=512;
            	if (recToDB) {
					recordToDatabase(nextID, "" + fileName.getText(), extension);
					Comparison c = parseFiles(new FileInputStream(PATH_TO_FILE+"/"+FOLDER_NAME+"/"+fileName.getText()+extension),0);
					query.appendData("ID", "" + nextDBID);
					query.appendData("Title", "" + fileName.getText());
					query.appendData("Dominant", "" + c.getFreq());
					query.appendData("Average", "" + c.getAvg());
					query.appendData("MaxAmp", "" + c.getMaxAmplitude());
					query.appendData("MinAmp", "" + c.getMinAmplitude());
					query.addRow();
				}
				nextID++;
				nextDBID++;
				
			}*/
		}
		catch (Exception e) {
			
		}
		finally {
			super.onDestroy();
		}
		
	}
	
	private InfoDatObject[] getIDOsFromDB() {
		String[] cols=new String[colNames.size()-1];
		for (int j=0; j < colNames.size()-1; j++) {
			cols[j]=colNames.get(j);
		}
		ArrayList<String> dbVals=query.getDataNS(cols, null, null, null, null);
		InfoDatObject[] retVal=new InfoDatObject[dbVals.size()/cols.length];
		
		int ctr=0;
    	for (int i=0; i<dbVals.size(); i+=cols.length) {
			  //Comparison c = new Comparison(dbVals.get(i), Double.valueOf(dbVals.get(i+1)), Double.valueOf(dbVals.get(i+2)), Double.valueOf(dbVals.get(i+3)), Double.valueOf(dbVals.get(i+4)));
			  //staticVals[i/5]=c;
    		String nam=dbVals.get(i);
    		double[] frqs=new double[] {Double.valueOf(dbVals.get(i+1)), Double.valueOf(dbVals.get(i+5)), Double.valueOf(dbVals.get(i+9))};
    		double[] avs=new double[] {Double.valueOf(dbVals.get(i+2)), Double.valueOf(dbVals.get(i+6)), Double.valueOf(dbVals.get(i+10))};
    		double[] mxs=new double[] {Double.valueOf(dbVals.get(i+3)), Double.valueOf(dbVals.get(i+7)), Double.valueOf(dbVals.get(i+11))};
    		double[] mns=new double[] {Double.valueOf(dbVals.get(i+4)), Double.valueOf(dbVals.get(i+8)), Double.valueOf(dbVals.get(i+12))};
    		retVal[ctr]=new InfoDatObject(nam, frqs, avs, mxs, mns);
    		ctr++;
		}
    	return retVal;
	}
	
	private String writeServerPacket(InfoDatObject ido) {
		String retVal="";
		String dlm=",";
		String titleReplacement=" ";
		double[] fFreqs=ido.getfFreqs();
		double[] avs=ido.getAvgs();
		double[] mxs=ido.getMaxes();
		double[] mns=ido.getMins();
		
		retVal+=fFreqs[0] + dlm + fFreqs[1] + dlm + fFreqs[2] +
			dlm + avs[0] + dlm + avs[1] + dlm + avs[2] + dlm + mxs[0] + dlm +
			mxs[1] + dlm + mxs[2] + dlm + mns[0] + dlm + mns[1] + dlm + mns[2] + dlm + ido.getName();
		
		return retVal;
	}
	
	private class InfoDatObject {
		private String name;
		private double[] fFreqs;
		private double[] avgs;
		private double[] maxes;
		private double[] mins;
		
		public InfoDatObject(double[] freqs, double[] avs, double[] mxs, double[] mns) {
			setfFreqs(freqs);
			setAvgs(avs);
			setMaxes(mxs);
			setMins(mns);
		}
		
		public InfoDatObject(String nam, double[] freqs, double[] avs, double[] mxs, double[] mns) {
			setName(nam);
			setfFreqs(freqs);
			setAvgs(avs);
			setMaxes(mxs);
			setMins(mns);
		}
		
		public void setfFreqs(double[] fFreqs) {
			this.fFreqs = fFreqs;
		}
		public double[] getfFreqs() {
			return fFreqs;
		}
		public void setAvgs(double[] avgs) {
			this.avgs = avgs;
		}
		public double[] getAvgs() {
			return avgs;
		}
		public void setMaxes(double[] maxes) {
			this.maxes = maxes;
		}
		public double[] getMaxes() {
			return maxes;
		}
		public void setMins(double[] mins) {
			this.mins = mins;
		}
		public double[] getMins() {
			return mins;
		}
		public void setName(String nam) {
			this.name = nam;
		}
		public String getName() {
			return name;
		}
	}
}
